home *** CD-ROM | disk | FTP | other *** search
/ The Utilities Experience / The Utilities Experience - Volume 1.iso / software / icons+tools / iconian / sources / popupgadget.e < prev    next >
Text File  |  1995-12-22  |  32KB  |  1,163 lines

  1. /*
  2. *          PopUpButton Gadget Class
  3. *
  4. *          Copyright ©1995 by Chad Randall  mbissaymssiK Software
  5. *          All Rights Reserved.
  6. *
  7. *          This source is released for instructional purposes ONLY.
  8. *          This source is not to be modified or altered in any way.
  9. *
  10. *          If you would like me to add a feature, or remove a bug,
  11. *          PLEASE contact me at:
  12. *
  13. *          crandall@msen.com
  14. *           -or- 
  15. *          229 S.Washington St, Manchester, Michigan 48158-9680 USA
  16. */
  17.  
  18. ->  Best viewed with a TAB size of 2
  19.  
  20. /*  Programming notes
  21. *
  22. *    Remember, in libraries, E will not allow [2,x,3,y,5,z]:LONG... so, we always
  23. *    need to build taglists/structs in memory.  I haven't found an easy way to do this
  24. *    so far... so I have a "base" list in memory, alloc space, then copy it over, and 
  25. *    finally longptr[n]:=x the variable parts.  Is there an easier way?
  26. */
  27.  
  28. OPT PREPROCESS
  29. LIBRARY 'popup.gadget',4,0,'popupgadget 4.0 (4.10.95)' IS 
  30.         initPopUpClass,
  31.         freePopUpClass,
  32.         addObjectToList,
  33.         disposeObjects,
  34.         disposeObjectNodes,
  35.         buildPalette,
  36.         disposePalette,
  37.         addTextToList
  38.  
  39. /*
  40. # define bigger(x,y) (IF x>y THEN x ELSE y)
  41. # define smaller(x,y) (IF x<y THEN x ELSE y)
  42. # define limit(x,y,z) (IF x<y THEN y ELSE (IF x<z THEN x ELSE z))
  43. */
  44.  
  45. MODULE    'diskfont'
  46. MODULE    'devices/inputevent'
  47. MODULE    'exec/memory','exec/lists','exec/nodes'
  48. MODULE    'graphics','graphics/text','graphics/gfx','graphics/rastport'
  49. MODULE    'intuition/cghooks','intuition/classes','intuition/classusr','intuition/gadgetclass',
  50.                 'intuition/icclass','intuition/imageclass','intuition/intuition','intuition/screens'
  51. MODULE    'utility','utility/tagitem'
  52.  
  53. MODULE    'amigalib/boopsi'
  54. ->MODULE    'mod/boopsi'
  55. MODULE    'amigalib/lists'
  56. MODULE    'tools/installhook'
  57.  
  58. MODULE    'gadgets/popup'
  59.  
  60. MODULE    'mod/compare'
  61. MODULE    'mod/lists'
  62.  
  63. ->MODULE    'mod/libdebug'
  64.  
  65. OBJECT puinst
  66.     window:PTR TO window            -> Window that is opened when gadget is active.
  67.     objlist:PTR TO lh                    -> Points to a exec-linked list of "objects"
  68.     numobjs:LONG                            -> Number of objects displayed...no bigger than across*down
  69.     active:LONG                                -> Currently active object.
  70.     lastactive:LONG                        -> Unused, really...
  71.     original:LONG                            -> Last active one, incase of an abort.
  72.     frameobj:PTR TO image            -> Class allocated frame obj to display bevel boxes.
  73.     gridw:LONG
  74.     gridh:LONG                    -> Size of individual boxes.  All boxes must be the same size.
  75.     across:LONG
  76.     down:LONG                    -> Number of objects across and down.
  77.     lastsent:LONG
  78.     winx:INT
  79.     winy:INT
  80.     winw:INT
  81.     winh:INT
  82.     gadgetbordertype:INT
  83.     windowbordertype:INT
  84.     arrow:INT                                    -> Specifies that the user wants a "popup arrow" drawn.
  85.     imagespacing:INT
  86.     windowspacing:INT
  87.     autosize:INT
  88.     layout:INT
  89.     centerimages:INT
  90.     centergadgetimage:INT
  91.     selectmode:INT
  92.     popupmode:INT
  93. ENDOBJECT
  94.  
  95. PROC dispatchPopUpGad(cl:PTR TO iclass, o, msg:PTR TO msg)
  96. /*
  97. *        This is the main routine, coming from input.device (mainly),
  98. *        E needs A4 setup to a global area, but installhook takes care of
  99. *        that for us.
  100. */
  101.     DEF retval=FALSE
  102.     DEF switch
  103.  
  104.     IF (utilitybase=0) THEN utilitybase:=OpenLibrary('utility.library',36)
  105.  
  106.     switch:=msg.methodid
  107.     SELECT switch
  108.     CASE OM_NEW;retval:=pu_new(cl,o,msg)
  109.     CASE OM_DISPOSE;retval:=pu_dispose(cl,o,msg)
  110.     CASE OM_SET;retval:=pu_set(cl, o, msg)
  111.     CASE OM_UPDATE;retval:=pu_set(cl,o,msg)
  112.     CASE OM_GET;retval:=pu_get(cl, o, msg)
  113. ->    CASE OM_NOTIFY;retval:=pu_notify(cl,o,msg)
  114.     CASE GM_RENDER;retval:=pu_render(cl, o, msg)
  115.     CASE GM_GOACTIVE;retval:=pu_goactive(cl,o,msg)
  116.     CASE GM_HANDLEINPUT;retval:=pu_handleinput(cl,o,msg)
  117.     CASE GM_GOINACTIVE;retval:=pu_goinactive(cl,o,msg)
  118.     DEFAULT;retval:=doSuperMethodA(cl, o, msg)
  119.     ENDSELECT
  120. ENDPROC retval
  121.  
  122. PROC pu_goinactive(cl:PTR TO iclass,o:PTR TO object,gpgi:PTR TO gpgoinactive)
  123.     DEF g:PTR TO gadget
  124.     DEF inst:PTR TO puinst
  125.     DEF retval
  126.  
  127.     DEF rp
  128.     DEF gpr:PTR TO gprender
  129.  
  130.     retval:=doSuperMethodA(cl,o,gpgi)
  131.     g:=o
  132.     g.flags:=g.flags AND Not(GFLG_SELECTED)
  133.     inst:=INST_DATA(cl, o)
  134.     IF inst.window                        -> If we have a window opened, close it.
  135.         CloseWindow(inst.window)
  136.         inst.window:=0
  137.     ENDIF
  138.     notifyactive(cl, o, 0, gpgi.ginfo,TRUE)    -> Signal the window we are dying, and our last active was...
  139.     rp:=ObtainGIRPort(gpgi.ginfo)
  140.     IF (rp)
  141.         NEW gpr
  142.         gpr.methodid:=GM_RENDER
  143.         gpr.ginfo:=gpgi.ginfo
  144.         gpr.rport:=rp
  145.         gpr.redraw:=GREDRAW_UPDATE
  146.         doMethodA(o,gpr)
  147.         ReleaseGIRPort(rp)
  148.         END gpr
  149.     ENDIF
  150. ->    pu_render(cl, o, gpgi)        -> Rerender our unselected imagery.
  151. ENDPROC retval
  152.  
  153. PROC pu_handleinput(cl:PTR TO iclass,o:PTR TO object,gpi:PTR TO gpinput)
  154.     DEF g:PTR TO gadget
  155.     DEF switch,ie:PTR TO inputevent
  156.     DEF retval=GMR_MEACTIVE
  157.     DEF inst:PTR TO puinst
  158.     DEF ie_switch
  159.  
  160.     g:=o
  161.     inst:=INST_DATA(cl, o)
  162.     ie:=gpi.ievent
  163.     WHILE ((ie) AND (retval=GMR_MEACTIVE))
  164.         ie_switch:=ie.class
  165.         SELECT ie_switch
  166.         CASE IECLASS_RAWMOUSE
  167.             switch:=ie.code
  168.             IF (switch=SELECTDOWN) THEN switch:=MENUDOWN  -> Handles when we are "Activated"
  169.             IF (switch=MENUUP) THEN switch:=SELECTUP
  170.             SELECT switch
  171.             CASE SELECTUP
  172.                 checkmouse(gpi,inst,g)
  173.                 notifyactive(cl, o, 0, gpi.ginfo)
  174.                 IF (gpi.mousex < 0) OR (gpi.mousex > g.width) OR (gpi.mousey < 0) OR (gpi.mousey > g.height)
  175.                     retval:=GMR_NOREUSE OR GMR_VERIFY
  176.                 ELSE
  177.                     retval:=GMR_NOREUSE
  178.                 ENDIF
  179.             CASE MENUDOWN
  180.                 changeactive(inst,gpi.ginfo.drinfo,inst.original)
  181.                 notifyactive(cl, o, 0, gpi.ginfo)
  182.                 retval:=GMR_REUSE
  183.             DEFAULT
  184.                 checkmouse(gpi,inst,g)
  185.             ENDSELECT
  186.         CASE IECLASS_TIMER
  187.             IF (inst.window)
  188.                 checkmouse(gpi,inst,g)
  189.                 IF ((g.activation AND GACT_RELVERIFY)=0) THEN notifyactive(cl, o, OPUF_INTERIM, gpi.ginfo)
  190.             ENDIF
  191.         ENDSELECT
  192.         ie:=ie.nextevent
  193.     ENDWHILE
  194. ENDPROC retval
  195.  
  196. PROC checkmouse(gpi:PTR TO gpinput,inst:PTR TO puinst,g:PTR TO gadget)
  197.     DEF winx,winy,over,a,b
  198.     IF ((inst.window) AND (gpi.ginfo.window))
  199.         winx:=gpi.ginfo.window.leftedge-inst.winx+g.leftedge-inst.window.leftedge+gpi.mousex
  200.         winy:=gpi.ginfo.window.topedge-inst.winy+g.topedge-inst.window.topedge+gpi.mousey
  201.         IF ((winx<0) OR (winx>=inst.winw) OR (winy<0) OR (winy>=inst.winh))
  202.             changeactive(inst,gpi.ginfo.drinfo,inst.original)
  203.         ELSE
  204.             a:=(winx/inst.gridw)
  205.             b:=(winy/inst.gridh)
  206.             over:=a+(b*inst.across)
  207.             changeactive(inst,gpi.ginfo.drinfo,over)
  208.         ENDIF
  209.     ENDIF        
  210. ENDPROC
  211.  
  212. PROC changeactive(inst:PTR TO puinst,drawinfo,new)
  213.     IF (inst.active<>new)
  214.         IF ((new>=0) AND (new<=inst.numobjs))
  215.             inst.lastactive:=inst.active
  216.             inst.active:=new
  217.             updatewindow(inst,drawinfo,inst.active,inst.lastactive)
  218.         ENDIF
  219.     ENDIF
  220. ENDPROC
  221.  
  222. PROC pu_get(cl:PTR TO iclass,o:PTR TO object,opg:PTR TO opget)
  223.     DEF retval
  224.     DEF inst:PTR TO puinst
  225.     DEF switch
  226.     DEF longptr:PTR TO LONG
  227.     inst:=INST_DATA(cl,o)
  228.     switch:=opg.attrid
  229.     longptr:=opg.storage
  230.     SELECT switch
  231.     CASE PUA_ACTIVE
  232.         longptr[0]:=inst.active
  233.         retval:=TRUE
  234.     CASE PUA_NUMBEROFOBJECTS
  235.         longptr[0]:=inst.numobjs+1
  236.         retval:=TRUE
  237.     CASE PUA_ROWS
  238.         longptr[0]:=inst.down
  239.         retval:=TRUE
  240.     CASE PUA_COLUMNS
  241.         longptr[0]:=inst.across
  242.         retval:=TRUE
  243.     DEFAULT
  244.         retval:=doSuperMethodA(cl,o,opg)
  245.     ENDSELECT    
  246. ENDPROC retval
  247.  
  248. PROC pu_new(cl:PTR TO iclass,o:PTR TO object,ops:PTR TO opset)
  249.     DEF inst:PTR TO puinst
  250.     DEF object:PTR TO object
  251.  
  252.     IF (object:=doSuperMethodA(cl, o, ops))
  253.         inst:=INST_DATA(cl, object)
  254.         inst.objlist:=GetTagData(PUA_OBJECTS,0,ops.attrlist)
  255.         inst.active:=GetTagData(PUA_ACTIVE,0,ops.attrlist)
  256.         inst.arrow:=GetTagData(PUA_POPUPARROW,PUARROW_NONE,ops.attrlist)
  257.         inst.across:=bigger(GetTagData(PUA_COLUMNS,1,ops.attrlist),1)
  258.         inst.down:=bigger(GetTagData(PUA_ROWS,1,ops.attrlist),1)
  259.         inst.gadgetbordertype:=GetTagData(PUA_GADGETBORDER,-1,ops.attrlist)
  260.         inst.windowbordertype:=GetTagData(PUA_WINDOWBORDER,-1,ops.attrlist)
  261.         inst.windowspacing:=GetTagData(PUA_WINDOWSPACING,FALSE,ops.attrlist)
  262.         inst.imagespacing:=GetTagData(PUA_IMAGESPACING,FALSE,ops.attrlist)
  263.         inst.autosize:=GetTagData(PUA_AUTOGADGETRESIZE,FALSE,ops.attrlist)
  264.         inst.layout:=GetTagData(PUA_AUTOWINDOWLAYOUT,FALSE,ops.attrlist)
  265.         inst.centerimages:=GetTagData(PUA_CENTERIMAGES,TRUE,ops.attrlist)
  266.         inst.centergadgetimage:=GetTagData(PUA_CENTERGADGETIMAGE,TRUE,ops.attrlist)
  267.         inst.selectmode:=GetTagData(PUA_SELECTMODE,PUSELECTMODE_NORMAL,ops.attrlist)
  268.         inst.popupmode:=GetTagData(PUA_POPUPMODE,PUPOPUPMODE_NORMAL,ops.attrlist)
  269.  
  270.         inst.frameobj:=NewObjectA(NIL,'frameiclass',[IA_RECESSED,FALSE,IA_EDGESONLY,FALSE,TAG_END])
  271.                                         /* The above is legal in an E-built library, because it is STATIC. */
  272.  
  273.         IF ((inst.objlist) AND (inst.frameobj))
  274.             layouteverything(object,inst)
  275.         ELSE
  276.             coerceMethodA(cl,o,[OM_DISPOSE,0,TAG_END]:LONG)
  277.             object:=NIL
  278.         ENDIF
  279.     ENDIF
  280. ENDPROC object
  281.  
  282. PROC layouteverything(g:PTR TO gadget,inst:PTR TO puinst)
  283.     DEF node:PTR TO imagenode,next
  284.     DEF i=0
  285.     DEF w,h,gw,gh
  286.     DEF longptr:PTR TO LONG
  287.     DEF im:PTR TO image
  288.     
  289.     inst.numobjs:=0
  290.     inst.gridw:=0
  291.     inst.gridh:=0
  292.     node:=inst.objlist.head
  293.     REPEAT
  294.         next:=node.listnode.succ
  295.         IF (next)
  296.             IF (node.object)
  297.                 w,h:=maxsize(node.object.width,node.object.height,node.frametype)
  298.                 IF (inst.imagespacing)
  299.                     w:=w+4
  300.                     h:=h+4
  301.                 ENDIF
  302.                 inst.gridw:=bigger(w,inst.gridw)
  303.                 inst.gridh:=bigger(h,inst.gridh)
  304.             ENDIF
  305.             IF (node.selobject)
  306.                 w,h:=maxsize(node.selobject.width,node.selobject.height,node.selframetype)
  307.                 IF (inst.imagespacing)
  308.                     w:=w+4
  309.                     h:=h+4
  310.                 ENDIF
  311.                 inst.gridw:=bigger(w,inst.gridw)
  312.                 inst.gridh:=bigger(h,inst.gridh)
  313.             ENDIF
  314.             inst.numobjs:=inst.numobjs+1
  315.         ENDIF
  316.         node:=next
  317.     UNTIL (next=0)
  318.     inst.numobjs:=inst.numobjs-1
  319. ->->->    inst.numobjs:=smaller(i-1,((inst.across*inst.down)-1))
  320.     node:=inst.objlist.head
  321.     REPEAT
  322.         next:=node.listnode.succ
  323.         IF (next)
  324.             IF (inst.centerimages)
  325.                 IF (node.object)
  326.                     node.private_offsetx:=(inst.gridw-node.object.width)/2
  327.                     node.private_offsety:=(inst.gridh-node.object.height)/2
  328.                 ENDIF
  329.                 IF (node.selobject)
  330.                     node.private_sel_offsetx:=((inst.gridw-node.selobject.width)/2)
  331.                     node.private_sel_offsety:=((inst.gridh-node.selobject.height)/2)
  332.                 ENDIF
  333.             ELSE
  334.                 w:=0
  335.                 h:=0
  336.                 gw:=0
  337.                 gh:=0
  338.                 IF (node.frametype>=0) THEN    w,h:=maxsize(0,0,node.frametype)
  339.                 IF (node.selobject)
  340.                     IF (node.selframetype>=0) THEN gw,gh:=maxsize(0,0,node.selframetype)
  341.                 ENDIF
  342.                 node.private_offsetx:=w/2
  343.                 node.private_offsety:=h/2
  344.                 node.private_sel_offsetx:=gw/2
  345.                 node.private_sel_offsety:=gh/2
  346.             ENDIF
  347.         ENDIF
  348.         node:=next
  349.     UNTIL (next=0)
  350.     gw:=0
  351.     gh:=0
  352.     IF (inst.autosize)
  353.         IF (g.gadgetrender<>0)
  354.             im:=g.gadgetrender
  355.             gw:=im.width
  356.             gh:=im.height
  357.             IF (g.selectrender<>0)
  358.                 im:=g.selectrender
  359.                 gw:=bigger(gw,im.width)
  360.                 gh:=bigger(gh,im.height)
  361.             ENDIF
  362.         ELSE
  363.             gw:=inst.gridw
  364.             gh:=inst.gridh
  365.         ENDIF
  366.         IF (inst.gadgetbordertype>=0)
  367.             gw,gh:=maxsize(gw,gh,inst.gadgetbordertype)
  368.         ENDIF
  369.         IF (inst.arrow=PUARROW_POPUP)
  370.             gw:=gw+16
  371.         ENDIF
  372.         longptr:=New(64)
  373.         longptr[0]:=GA_WIDTH
  374.         longptr[1]:=gw
  375.         longptr[2]:=GA_HEIGHT
  376.         longptr[3]:=gh
  377.         longptr[4]:=TAG_END
  378.         SetAttrsA(g,longptr)
  379.         Dispose(longptr)
  380.     ENDIF
  381. ENDPROC
  382.  
  383. PROC pu_dispose(cl:PTR TO iclass,o:PTR TO object,msg:PTR TO msg)
  384.     DEF inst:PTR TO puinst
  385.     inst:=INST_DATA(cl,o)
  386.     IF inst.window
  387.         CloseWindow(inst.window)
  388.         inst.window:=0
  389.     ENDIF
  390.     IF inst.frameobj
  391.         DisposeObject(inst.frameobj)
  392.         inst.frameobj:=0
  393.     ENDIF
  394.     RETURN doSuperMethodA(cl,o,msg)
  395. ENDPROC
  396.  
  397. PROC pu_set(cl:PTR TO iclass,o:PTR TO object,ops:PTR TO opset)
  398.     DEF inst:PTR TO puinst
  399.     DEF rp,tag:PTR TO tagitem
  400.     DEF retval
  401.     DEF gpr:PTR TO gprender
  402.     DEF newimagestate=0
  403.     DEF opu:PTR TO opupdate
  404.     DEF opn:PTR TO opnotify
  405.     DEF longptr:PTR TO LONG
  406.     DEF original
  407.     DEF newlayout=FALSE,ox,oy,ow,oh
  408.  
  409.     inst:=INST_DATA(cl, o)
  410.     ox:=o::gadget.leftedge
  411.     oy:=o::gadget.topedge
  412.     ow:=o::gadget.width
  413.     oh:=o::gadget.height
  414.     original:=inst.active
  415.     retval:=doSuperMethodA(cl, o, ops)
  416.     IF (ops.attrlist)
  417.         IF (tag:=FindTagItem(GA_DISABLED,ops.attrlist)) THEN newimagestate:=TRUE
  418.         IF (tag:=FindTagItem(GA_IMAGE,ops.attrlist))
  419.             newimagestate:=TRUE
  420.             newlayout:=TRUE
  421.         ENDIF
  422.         IF (tag:=FindTagItem(GA_SELECTRENDER,ops.attrlist))
  423.             newimagestate:=TRUE
  424.             newlayout:=TRUE
  425.         ENDIF
  426.         IF (tag:=FindTagItem(PUA_ACTIVE,ops.attrlist))
  427.             inst.active:=limit(tag.data,0,inst.numobjs)
  428.             IF (inst.active<>original) THEN newimagestate:=TRUE
  429.         ENDIF
  430.         IF (tag:=FindTagItem(PUA_ROWS,ops.attrlist))
  431.             inst.down:=tag.data
  432.         ENDIF
  433.         IF (tag:=FindTagItem(PUA_COLUMNS,ops.attrlist))
  434.             inst.across:=tag.data
  435.         ENDIF
  436.         IF (tag:=FindTagItem(PUA_AUTOGADGETRESIZE,ops.attrlist))
  437.             inst.autosize:=tag.data
  438.         ENDIF
  439.         IF (tag:=FindTagItem(PUA_WINDOWSPACING,ops.attrlist))
  440.             inst.windowspacing:=tag.data
  441.         ENDIF
  442.         IF (tag:=FindTagItem(PUA_IMAGESPACING,ops.attrlist))
  443.             inst.imagespacing:=tag.data
  444.             newlayout:=TRUE
  445.         ENDIF
  446.         IF (tag:=FindTagItem(PUA_WINDOWBORDER,ops.attrlist))
  447.             inst.windowbordertype:=tag.data
  448.         ENDIF
  449.         IF (tag:=FindTagItem(PUA_GADGETBORDER,ops.attrlist))
  450.             inst.gadgetbordertype:=tag.data
  451.             newlayout:=TRUE
  452.             newimagestate:=TRUE
  453.         ENDIF
  454.         IF (tag:=FindTagItem(PUA_CENTERGADGETIMAGE,ops.attrlist))
  455.             inst.centergadgetimage:=tag.data
  456.             newimagestate:=TRUE
  457.             newlayout:=TRUE
  458.         ENDIF
  459.         IF (tag:=FindTagItem(PUA_POPUPARROW,ops.attrlist))
  460.             inst.arrow:=tag.data
  461.             newlayout:=TRUE
  462.             newimagestate:=TRUE
  463.         ENDIF
  464.         IF (tag:=FindTagItem(PUA_CENTERIMAGES,ops.attrlist))
  465.             inst.centerimages:=tag.data
  466.             newlayout:=TRUE
  467.             newimagestate:=TRUE
  468.         ENDIF
  469.         IF (newlayout) THEN layouteverything(o,inst)
  470.         IF ((ox<>o::gadget.leftedge) OR (oy<>o::gadget.topedge) OR (ow<>o::gadget.width) OR (oh<>o::gadget.height))
  471.             rp:=ObtainGIRPort(ops.ginfo)
  472.             IF (rp)
  473.                 EraseRect(rp,ox,oy,ox+ow-1,oy+oh-1)
  474.                 ReleaseGIRPort(rp)
  475.             ENDIF
  476.             newimagestate:=TRUE
  477.         ENDIF
  478.         IF (newimagestate)
  479.             retval:=1                            -> Notify app a visual change will take place.
  480.             rp:=ObtainGIRPort(ops.ginfo)
  481.             IF (rp)
  482.                 NEW gpr
  483.                 gpr.methodid:=GM_RENDER
  484.                 gpr.ginfo:=ops.ginfo
  485.                 gpr.rport:=rp
  486.                 gpr.redraw:=GREDRAW_UPDATE
  487.                 doMethodA(o,gpr)
  488.                 ReleaseGIRPort(rp)
  489.                 END gpr
  490.             ENDIF
  491.             opn:=New(64)
  492.             longptr:=New(64)
  493.             longptr[0]:=TAG_END
  494.             opn.methodid:=OM_NOTIFY
  495.             opn.attrlist:=longptr
  496.             opn.ginfo:=ops.ginfo
  497.             opn.flags:=0
  498.             doMethodA(o,opn)
  499.             Dispose(opn)
  500.             Dispose(longptr)
  501.             ->            notifyactive(cl, o, 0, ops.ginfo)
  502.         ENDIF
  503.     ENDIF
  504. ENDPROC retval
  505.  
  506.  
  507. /*
  508. PROC pu_notify(cl:PTR TO iclass, o:PTR TO object, opu:PTR TO opupdate)
  509.     DEF retval
  510.     DEF longptr:PTR TO LONG
  511.     DEF inst:PTR TO puinst
  512.     DEF opn:PTR TO opnotify
  513.  
  514.     inst:=INST_DATA(cl,o)
  515.     longptr:=New(64)
  516.     longptr[0]:=GA_ID
  517.     longptr[1]:=o::gadget.gadgetid
  518.     longptr[2]:=PUA_ACTIVE
  519.     longptr[3]:=inst.active
  520.     IF (opu.attrlist=NIL)
  521.         longptr[4]:=TAG_END
  522.     ELSE
  523.         longptr[4]:=TAG_MORE
  524.         longptr[5]:=opu.attrlist
  525.     ENDIF
  526.     opn:=New(64)
  527.     opn.methodid:=OM_NOTIFY
  528.     opn.attrlist:=longptr
  529.     opn.ginfo:=opu.ginfo
  530.     opn.flags:=opu.flags
  531.     opn.flags:=0
  532.     retval:=coerceMethodA(cl,o,opn)
  533. ->    retval:=doSuperMethodA(cl,o,opn)
  534.     Dispose(opn)
  535.     Dispose(longptr)
  536. ENDPROC retval
  537. */
  538.  
  539. PROC pu_goactive(cl:PTR TO iclass, o:PTR TO object, gpi:PTR TO gpinput)
  540.     DEF retval=GMR_MEACTIVE,switch
  541.     DEF rp:PTR TO rastport
  542.     DEF inst:PTR TO puinst
  543.     DEF gi:PTR TO gadgetinfo
  544.     DEF g:PTR TO gadget
  545.     DEF left,top,midx,midy
  546.     DEF width,height,act
  547.     DEF gprender:PTR TO gprender
  548.     DEF longptr:PTR TO LONG
  549.     DEF duplicate_rp:PTR TO rastport
  550.  
  551.     g:=o
  552.     gi:=gpi.ginfo
  553.     inst:=INST_DATA(cl, g)
  554.     IF (g.flags AND GFLG_DISABLED) THEN RETURN GMR_NOREUSE
  555.     doSuperMethodA(cl,o,gpi)
  556. ->    IF (gpi.ievent)
  557.         g.flags:=g.flags OR GFLG_SELECTED
  558.         IF (rp:=ObtainGIRPort(gi))
  559.  
  560.             NEW gprender,duplicate_rp
  561.             CopyMem(rp,duplicate_rp,SIZEOF rastport)
  562.             gprender.methodid:=GM_RENDER
  563.             gprender.ginfo:=gi
  564.             gprender.rport:=duplicate_rp
  565.             gprender.redraw:=GREDRAW_UPDATE
  566.             doMethodA(o,gprender)
  567.             END gprender,duplicate_rp
  568.  
  569.             ReleaseGIRPort(rp)
  570.  
  571.             IF ((inst.window=0) AND (gi.window))
  572.                 inst.winw:=(inst.across*inst.gridw)
  573.                 inst.winh:=(inst.down*inst.gridh)
  574.                 width,height:=maxsize(inst.winw,inst.winh,inst.windowbordertype)
  575.                 IF (inst.windowspacing)
  576.                     width:=width+4
  577.                     height:=height+4
  578.                 ENDIF
  579.                 inst.winx:=((width-inst.winw)/2)
  580.                 inst.winy:=((height-inst.winh)/2)
  581.                 midx:=gpi.mousex-((g.width/2)+(IF (inst.arrow=PUARROW_POPUP) THEN 8 ELSE 0))
  582.                 midy:=gpi.mousey-(g.height/2)
  583.  
  584.                 left:=(gi.window.leftedge+g.leftedge+(g.width/2))+(IF (inst.arrow=PUARROW_POPUP) THEN 8 ELSE 0)-(width/2)
  585.                 top:=(gi.window.topedge+g.topedge+(g.height/2))-(height/2)
  586.                 switch:=inst.popupmode
  587.                 SELECT switch
  588.                 CASE PUPOPUPMODE_CENTER;NOP
  589.                 CASE PUPOPUPMODE_TOPSIDE;top:=gi.window.topedge+g.topedge-height
  590.                 CASE PUPOPUPMODE_BOTTOMSIDE;top:=gi.window.topedge+g.topedge+g.height
  591.                 CASE PUPOPUPMODE_LEFTSIDE;left:=gi.window.leftedge+g.leftedge-width
  592.                 CASE PUPOPUPMODE_RIGHTSIDE;left:=gi.window.leftedge+g.leftedge+g.width
  593.                 DEFAULT
  594.                     left:=(((gi.window.leftedge+g.leftedge+(g.width/2))-((inst.active - ((inst.active/inst.across)*inst.across)) * inst.gridw) - (inst.gridw/2))-inst.winx) +(IF (inst.arrow=PUARROW_POPUP) THEN 8 ELSE 0)+midx
  595.                     top:=((gi.window.topedge+g.topedge+(g.height/2))-((inst.active/inst.across)*inst.gridh) - (inst.gridh/2))-inst.winy+midy
  596.                 ENDSELECT
  597.                 IF inst.selectmode=PUSELECTMODE_NOACTIVE
  598.                     inst.active:=-1
  599.                 ENDIF
  600.  
  601.                 longptr:=New(240)
  602.                 CopyMem({deftags},longptr,200)
  603.                 longptr[1]:=left
  604.                 longptr[3]:=top
  605.                 longptr[5]:=width
  606.                 longptr[7]:=height
  607.                 longptr[9]:=gi.screen
  608.                 inst.window:=OpenWindowTagList(0,longptr)    -> We cannot use [tags]:LONG because this is a library!
  609.                 Dispose(longptr)
  610.                 inst.lastactive:=-1
  611.                 inst.original:=inst.active
  612.                 updatewindow(inst,gpi.ginfo.drinfo,-1,-1)
  613.                 IF (inst.windowbordertype>=0)
  614.                     IF inst.window
  615.                         longptr:=New(64)
  616.                         CopyMem({frametaglist},longptr,64)
  617.                         longptr[1]:=width
  618.                         longptr[3]:=height
  619.                         longptr[5]:=FALSE
  620.                         longptr[7]:=inst.windowbordertype
  621.                         SetAttrsA(inst.frameobj,longptr)
  622.                         Dispose(longptr)
  623.                          DrawImageState(inst.window.rport,inst.frameobj,0,0,IDS_NORMAL,gpi.ginfo.drinfo)
  624.                      ENDIF
  625.                 ENDIF
  626.             ENDIF
  627.             retval:=GMR_MEACTIVE
  628.         ENDIF
  629. ->    ELSE
  630. ->        retval:=GMR_NOREUSE
  631. ->    ENDIF
  632. ENDPROC retval
  633.  
  634. PROC updatewindow(inst:PTR TO puinst,drawinfo:PTR TO drawinfo,updatethisone,andthisone)
  635.     DEF xx,yy
  636.     DEF node:PTR TO imagenode
  637.     DEF next
  638.     DEF cur
  639.     IF inst.window=0 THEN RETURN
  640.     node:=inst.objlist.head
  641.     FOR yy:=0 TO (inst.down-1)
  642.         FOR xx:=0 TO (inst.across-1)
  643.             next:=node.listnode.succ
  644.             IF (next)
  645.                 cur:=(yy*inst.across)+xx
  646.                 node.private_lastdrawn:=IF (inst.active=cur) THEN TRUE ELSE FALSE
  647.                 IF ((updatethisone=-1) OR (updatethisone=cur) OR (andthisone=cur))
  648.                     drawnode(inst.window.rport,inst.winx+(xx*inst.gridw),inst.winy+(yy*inst.gridh),inst.gridw,inst.gridh,node,inst,drawinfo,node.private_lastdrawn)
  649.                 ENDIF
  650.                 node:=next
  651.             ENDIF
  652.         ENDFOR
  653.     ENDFOR 
  654.     inst.lastactive:=inst.active
  655. ENDPROC
  656.  
  657. PROC drawnode(rast,x,y,w,h,node:PTR TO imagenode,inst:PTR TO puinst,drawinfo:PTR TO drawinfo,sel)
  658.     DEF obj,ids=IDS_NORMAL,offx,offy
  659.     DEF longptr:PTR TO LONG,frame
  660.     IF (node)
  661.         SetAPen(rast,drawinfo.pens[IF sel THEN node.selfillcolor ELSE BACKGROUNDPEN])
  662.         RectFill(rast,x,y,(x+w-1),(y+h-1))
  663.         obj:=node.object
  664.         offx:=node.private_offsetx
  665.         offy:=node.private_offsety
  666.         frame:=node.frametype
  667.         IF (sel)
  668.             frame:=node.selframetype
  669.             IF node.selobject
  670.                 obj:=node.selobject
  671.                 offx:=node.private_sel_offsetx
  672.                 offy:=node.private_sel_offsety
  673.             ELSE
  674.                 ids:=IDS_SELECTED
  675.             ENDIF
  676.         ENDIF
  677.         IF (frame>=0)
  678.             longptr:=New(64)
  679.             CopyMem({frametaglist},longptr,64)
  680.             longptr[1]:=w
  681.             longptr[3]:=h
  682.             longptr[5]:=IF (sel) THEN TRUE ELSE FALSE
  683.             longptr[7]:=frame
  684.             SetAttrsA(inst.frameobj,longptr)
  685.             Dispose(longptr)
  686.              DrawImageState(rast,inst.frameobj,x,y,IDS_NORMAL,drawinfo)
  687.         ENDIF
  688.         DrawImageState(rast,obj,x+offx,y+offy,ids,drawinfo)
  689.     ENDIF
  690. ENDPROC
  691.  
  692. frametaglist:
  693.     LONG    IA_WIDTH,0,
  694.                 IA_HEIGHT,0,
  695.                 IA_RECESSED,0,
  696.                 IA_FRAMETYPE,0,
  697.                 IA_EDGESONLY,TRUE,
  698.                 IA_BGPEN,0,
  699.                 IA_FGPEN,0,
  700.                 TAG_END
  701.  
  702. PROC maxsize(bw,bh,frametype)
  703. -> Used to be: PROC maxsize(inst:PTR TO puinst,o1:PTR TO image,frametype,drawinfo)
  704. ->    DEF framebox:PTR TO impframebox
  705. ->    DEF fbox:PTR TO ibox
  706. ->    DEF cbox:PTR TO ibox
  707.     DEF aw=0,ah=0
  708.  
  709.     SELECT frametype
  710.     CASE FRAME_DEFAULT;aw:=2;ah:=2
  711.     CASE FRAME_BUTTON;aw:=4;ah:=2
  712.     CASE FRAME_RIDGE;aw:=8;ah:=4
  713.     CASE FRAME_ICONDROPBOX;aw:=12;ah:=6
  714.     ENDSELECT
  715.     bw:=bw+aw
  716.     bh:=bh+ah
  717.  
  718. /*
  719.  
  720. * Unfortunatly, frameiclass always seems to return +4,+4 for it's dimensions
  721. * after giving it IM_FRAMEBOX... so, I'm deactivating this code until I discover
  722. * why...    I've tried ALOT of different things... no luck
  723.  
  724. ->        IF drawinfo=0 THEN drawinfo:=inst.drawinfo    ...PUA_DRAWINFO no longer...
  725.         IF drawinfo=0 THEN RETURN o1.width+16,o1.height+16
  726.         SetAttrsA(inst.frameobj,[IA_FRAMETYPE,frametype,IA_DOUBLEEMBOSS,TRUE,TAG_END])
  727.         framebox:=New(64)
  728.         cbox:=New(32)
  729.         fbox:=New(32)
  730.         cbox.width:=o1.width
  731.         cbox.height:=o1.height
  732.         cbox.left:=0
  733.         cbox.top:=0
  734.         framebox.methodid:=IM_FRAMEBOX
  735.         framebox.contentsbox:=cbox
  736.         framebox.framebox:=fbox
  737.         framebox.drinfo:=drawinfo
  738.         framebox.frameflags:=0
  739.         doMethodA(inst.frameobj,framebox)
  740.         w:=bigger(o1.width,fbox.width)
  741.         h:=bigger(o1.height,fbox.height)
  742.  
  743.         Dispose(framebox)
  744.         Dispose(cbox)
  745.         Dispose(fbox)
  746. */
  747. ENDPROC bw,bh
  748.  
  749. PROC notifyactive(cl:PTR TO iclass, o:PTR TO gadget, flags, ginfo,flag=FALSE)
  750.     DEF msg:PTR TO opnotify
  751.     DEF inst:PTR TO puinst
  752.     DEF longptr:PTR TO LONG
  753.  
  754.     inst:=INST_DATA(cl, o)
  755.     IF ((inst.active<>inst.lastsent) OR (flag=TRUE))
  756.         NEW msg
  757.         longptr:=New(40)
  758.         longptr[0]:=PUA_ACTIVE
  759.         longptr[1]:=inst.active
  760.         longptr[2]:=GA_ID
  761.         longptr[3]:=o.gadgetid
  762.         longptr[4]:=TAG_END
  763.         msg.methodid:=OM_NOTIFY
  764.         msg.attrlist:=longptr
  765.         msg.ginfo:=ginfo
  766.         msg.flags:=flags
  767.         doSuperMethodA(cl,o, msg)
  768.         END msg
  769.         Dispose(longptr)
  770.     ENDIF
  771.     inst.lastsent:=inst.active
  772. ENDPROC
  773.  
  774. -> Erase and rerender the gadget.
  775. PROC pu_render(cl:PTR TO iclass, o:PTR TO object, gpr:PTR TO gprender)
  776.     DEF inst:PTR TO puinst, orp, rp, retval=TRUE, pens:PTR TO INT
  777.     DEF g:PTR TO gadget
  778.     DEF node:PTR TO imagenode
  779.     DEF i
  780.     DEF issel
  781.     DEF shine,shadow
  782.     DEF xx,yy
  783.     DEF ox=0,oy=0
  784.     DEF longptr:PTR TO LONG,switch
  785.     DEF im:PTR TO image
  786.     DEF im2:PTR TO image
  787.  
  788.     g:=o
  789.     inst:=INST_DATA(cl, g)
  790.  
  791.     retval:=doSuperMethodA(cl,o,gpr)
  792.  
  793.     pens:=gpr.ginfo.drinfo.pens
  794.     IF gpr.methodid=GM_RENDER
  795.         o:=gpr.rport
  796.     ELSE
  797.         o:=ObtainGIRPort(gpr.ginfo)
  798.     ENDIF
  799.     IF (o)
  800.         rp:=New(SIZEOF rastport)
  801.         CopyMem(o,rp,SIZEOF rastport)
  802.         node:=inst.objlist.head
  803.         IF (inst.active>0)
  804.             FOR i:=0 TO inst.active-1
  805.                 IF (node) THEN node:=node.listnode.succ
  806.             ENDFOR
  807.         ENDIF
  808.         IF (node.listnode.succ)
  809.             issel:=(g.flags AND GFLG_SELECTED)
  810.             xx:=IF (inst.arrow=PUARROW_POPUP) THEN 8 ELSE 0
  811.             IF (inst.gadgetbordertype>=0)
  812.                 longptr:=New(64)
  813.                 CopyMem({frametaglist},longptr,64)
  814.                 longptr[1]:=g.width
  815.                 longptr[3]:=g.height
  816.                 longptr[5]:=IF (issel) THEN TRUE ELSE FALSE
  817.                 longptr[7]:=inst.gadgetbordertype
  818.                 longptr[9]:=FALSE
  819.                 SetAttrsA(inst.frameobj,longptr)
  820.                 Dispose(longptr)
  821.                 DrawImageState(rp,inst.frameobj,g.leftedge,g.topedge,IDS_NORMAL,gpr.ginfo.drinfo)
  822.                 ox,oy:=maxsize(0,0,inst.gadgetbordertype)
  823.                 ox:=ox/2
  824.                 oy:=oy/2
  825.              ELSE
  826.                 SetAPen(rp,pens[BACKGROUNDPEN])
  827.                 SetDrMd(rp,RP_JAM2)
  828.                 RectFill(rp,g.leftedge,g.topedge,g.leftedge+g.width,g.topedge+g.height)
  829.              ENDIF
  830.             im:=g.gadgetrender
  831.             IF ((issel) AND (g.selectrender<>0)) THEN im:=g.selectrender
  832.             IF (inst.centergadgetimage=FALSE) THEN ox:=ox+(xx*2)
  833.             IF (im)
  834.                 IF (inst.centergadgetimage)
  835.                     ox:=((g.width-im.width)/2)+xx
  836.                     oy:=((g.height-im.height)/2)
  837.                 ENDIF
  838.                  DrawImageState(rp,im,g.leftedge+ox,g.topedge+oy,IF (issel) THEN IDS_SELECTED ELSE IDS_NORMAL,gpr.ginfo.drinfo)
  839.             ELSE
  840.                 IF (inst.centergadgetimage)
  841.                     ox:=((g.width-inst.gridw)/2)+xx
  842.                     oy:=((g.height-inst.gridh)/2)
  843.                 ENDIF
  844.                 drawnode(rp,g.leftedge+ox,g.topedge+oy,inst.gridw,inst.gridh,node,inst,gpr.ginfo.drinfo,issel)
  845.             ENDIF
  846.  
  847.             IF (inst.arrow)
  848.                 IF (issel)
  849.                     shine:=pens[SHADOWPEN]
  850.                     shadow:=pens[SHINEPEN]
  851.                 ELSE
  852.                     shine:=pens[SHINEPEN]
  853.                     shadow:=pens[SHADOWPEN]
  854.                 ENDIF
  855.                 switch:=inst.arrow
  856.                 xx,yy:=maxsize(0,0,inst.gadgetbordertype)
  857.                 SELECT switch
  858.                 CASE PUARROW_POPUP
  859.                     ox:=g.leftedge+(xx/2)
  860.                     oy:=g.topedge+(yy/2)
  861.                     SetAPen(rp,shadow)
  862.                     Move(rp,ox+13,oy+1)
  863.                     Draw(rp,ox+13,oy+(g.height-yy-2))
  864.                     SetAPen(rp,shine)
  865.                     Move(rp,ox+14,oy+1)
  866.                     Draw(rp,ox+14,oy+(g.height-yy-2))
  867.                     xx:=ox+2
  868.                     yy:=g.topedge+(g.height/2)-4
  869.                     FOR ox:=xx TO xx+6 STEP 3
  870.                         FOR oy:=yy TO yy+6 STEP 3
  871.                             SetAPen(rp,shadow)
  872.                             WritePixel(rp,ox,oy)
  873.                             WritePixel(rp,ox+1,oy)
  874.                             WritePixel(rp,ox,oy+1)
  875.                             SetAPen(rp,shine)
  876.                             WritePixel(rp,ox+2,oy+1)
  877.                             WritePixel(rp,ox+2,oy+2)
  878.                             WritePixel(rp,ox+1,oy+2)
  879.                         ENDFOR
  880.                     ENDFOR
  881.                 CASE PUARROW_TINY
  882.                     xx:=g.leftedge+g.width-6-(xx/2)
  883.                     yy:=g.topedge+1+(yy/2)
  884.  
  885.                     SetAPen(rp,shadow)
  886.                     Move(rp,xx+1,yy)
  887.                     Draw(rp,xx+1,yy+6)
  888.                     Move(rp,xx+2,yy+6)
  889.                     Draw(rp,xx+5,yy+3)
  890.  
  891.                     SetAPen(rp,shine)
  892.                     Move(rp,xx,yy)
  893.                     Draw(rp,xx,yy+6)
  894.                     Move(rp,xx+2,yy+5)
  895.                     Draw(rp,xx+2,yy)
  896.                     Draw(rp,xx+5,yy+3)
  897.  
  898.                     SetAPen(rp,pens[BACKGROUNDPEN])
  899.                     Move(rp,xx+3,yy+2)
  900.                     Draw(rp,xx+3,yy+4)
  901.                     Draw(rp,xx+4,yy+3)
  902.                 ENDSELECT
  903.             ENDIF
  904.         ENDIF
  905.         IF (g.flags AND GFLG_DISABLED)
  906.             SetAPen(rp,pens[TEXTPEN])
  907.             SetDrMd(rp,RP_JAM1)
  908.             setafpt(rp,[%10001000100010000010001000100010],1)
  909.             RectFill(rp,g.leftedge,g.topedge,g.leftedge+g.width-1,g.topedge+g.height-1)
  910.         ENDIF
  911.         IF (gpr.methodid<>GM_RENDER) THEN ReleaseGIRPort(o)
  912.         Dispose(rp)
  913.     ELSE
  914.         retval:=FALSE
  915.     ENDIF
  916. ENDPROC retval
  917.  
  918. PROC setafpt(rast:PTR TO rastport,pattern,size)
  919.     rast.areaptrn:=pattern
  920.     rast.areaptsz:=size
  921. ENDPROC
  922.  
  923. deftags:
  924.     LONG    WA_LEFT,0,
  925.                 WA_TOP,0,
  926.                 WA_WIDTH,0,
  927.                 WA_HEIGHT,0,
  928.                 WA_CUSTOMSCREEN,0,
  929.                 WA_BORDERLESS,TRUE,
  930.                 WA_RMBTRAP,TRUE,
  931.                 WA_AUTOADJUST,TRUE,
  932.                 WA_ACTIVATE,FALSE,
  933.                 WA_NOCAREREFRESH,TRUE,
  934.                 WA_SIMPLEREFRESH,TRUE,
  935.                 TAG_END,TAG_END,
  936.                 TAG_END,TAG_END,
  937.                 TAG_END,TAG_END
  938.  
  939.     CHAR 0, '$VER: popup.gadget 4.0 (4.10.95)', 0,0
  940.  
  941. PROC freePopUpClass(cl)
  942.     FreeClass(cl)
  943.     IF utilitybase
  944.         CloseLibrary(utilitybase)
  945.         utilitybase:=0
  946.     ENDIF
  947. ENDPROC
  948. PROC initPopUpClass()
  949.     DEF cl:PTR TO iclass
  950.     utilitybase:=OpenLibrary('utility.library',36)
  951. ->    IF cl:=MakeClass(NIL, 'buttongclass', NIL, SIZEOF puinst, 0)
  952.     IF cl:=MakeClass(NIL, 'gadgetclass', NIL, SIZEOF puinst, 0)
  953.         installhook(cl.dispatcher, {dispatchPopUpGad})
  954.     ENDIF
  955. ENDPROC cl
  956.  
  957. PROC addObjectToList(list,object,frametype,selobject,selframetype,selfillcolor)
  958.     DEF node:PTR TO imagenode
  959.  
  960.     node:=AllocMem(SIZEOF imagenode,MEMF_ANY OR MEMF_CLEAR)
  961.     node.object:=object
  962.     node.frametype:=frametype
  963.     node.selobject:=selobject
  964.     node.selfillcolor:=selfillcolor
  965.     node.selframetype:=selframetype
  966.     node.private_iallocated:=-4
  967.     AddTail(list,node)
  968. ENDPROC node
  969.  
  970. PROC addTextToList(list,text,textattr:PTR TO textattr,drawinfo:PTR TO drawinfo) HANDLE
  971.     DEF rast:PTR TO rastport
  972.     DEF xor=0,w=0,h=0
  973.     DEF textextent:PTR TO textextent
  974.     DEF it1:PTR TO intuitext
  975.     DEF it2:PTR TO intuitext
  976.     DEF slen,textstring=0
  977.     DEF obj1,obj2
  978.     DEF longptr:PTR TO LONG
  979.     DEF node:PTR TO imagenode
  980.     DEF mytextattr=0:PTR TO textattr
  981.     DEF textfont=0:PTR TO textfont
  982.  
  983.     mytextattr:=AllocMem(SIZEOF textattr,MEMF_ANY OR MEMF_CLEAR)
  984.     IF (textattr)
  985.         mytextattr.name:=String(StrLen(textattr.name))
  986.         StrCopy(mytextattr.name,textattr.name)
  987.         mytextattr.ysize:=textattr.ysize
  988.         mytextattr.style:=textattr.style
  989.         mytextattr.flags:=textattr.flags
  990.     ELSE
  991.         mytextattr.name:='topaz.font'
  992.         mytextattr.ysize:=8
  993.     ENDIF
  994.     diskfontbase:=OpenLibrary('diskfont.library',36)
  995.     IF (diskfontbase)
  996.         textfont:=OpenDiskFont(mytextattr)
  997.         CloseLibrary(diskfontbase)
  998.     ELSE
  999.         textfont:=OpenFont(mytextattr)
  1000.     ENDIF
  1001.     IF (textfont)
  1002.         NEW rast,textextent
  1003.         slen:=StrLen(text)
  1004.         InitRastPort(rast)
  1005.         xor:=xor OR (IF ((textfont.style AND 1)<>(textattr.style AND 1)) THEN 1 ELSE 0)
  1006.         xor:=xor OR (IF ((textfont.style AND 2)<>(textattr.style AND 2)) THEN 2 ELSE 0)
  1007.         xor:=xor OR (IF ((textfont.style AND 4)<>(textattr.style AND 4)) THEN 4 ELSE 0)
  1008.         SetFont(rast,textfont)
  1009.         SetSoftStyle(rast,xor,7)
  1010.         TextExtent(rast,text,slen,textextent)
  1011.         w:=Abs(textextent.extent.minx)+Abs(textextent.extent.maxx)+1
  1012.         h:=Abs(textextent.extent.miny)+Abs(textextent.extent.maxy)+1
  1013.         END rast,textextent
  1014.         it1:=AllocMem(SIZEOF intuitext,MEMF_ANY OR MEMF_CLEAR)
  1015.         it2:=AllocMem(SIZEOF intuitext,MEMF_ANY OR MEMF_CLEAR)
  1016.         
  1017.         textstring:=String(StrLen(text))
  1018.         StrCopy(textstring,text,ALL)
  1019.         it1.itext:=textstring
  1020.         it2.itext:=textstring
  1021.         it1.frontpen:=6
  1022.         it1.backpen:=14
  1023.         it1.drawmode:=RP_JAM1
  1024.         it2.drawmode:=RP_JAM1
  1025.         it1.itextfont:=mytextattr
  1026.         it2.itextfont:=mytextattr
  1027.  
  1028.         longptr:=New(128)
  1029.         CopyMem({itexttags},longptr,128)
  1030.         longptr[1]:=w
  1031.         longptr[3]:=h
  1032.         longptr[5]:=it1
  1033.         longptr[7]:=drawinfo.pens[TEXTPEN]
  1034.         obj1:=NewObjectA(NIL,{itexticlass},longptr)
  1035.         longptr[5]:=it2
  1036.         longptr[7]:=drawinfo.pens[FILLTEXTPEN]
  1037.         obj2:=NewObjectA(NIL,{itexticlass},longptr)
  1038.         Dispose(longptr)
  1039.  
  1040.         IF ((obj1) AND (obj2))
  1041.             node:=addObjectToList(list,obj1,-1,obj2,FRAME_BUTTON,FILLPEN)
  1042.             node.private_iallocated:=-5
  1043.             node.private_itextn:=it1
  1044.             node.private_itexts:=it2
  1045.             node.private_textfont:=textfont
  1046.             node.private_textattr:=mytextattr
  1047.             node.private_text:=textstring
  1048.         ELSE
  1049.             CloseFont(textfont)
  1050.         ENDIF
  1051.     ELSE
  1052.         Raise(-1)
  1053.     ENDIF
  1054. EXCEPT
  1055.     IF (mytextattr.name) THEN DisposeLink(mytextattr.name)
  1056.     IF (textstring) THEN DisposeLink(textstring)
  1057.     IF (mytextattr) THEN FreeMem(mytextattr,SIZEOF textattr)
  1058.     IF (textfont) THEN CloseFont(textfont)
  1059. ENDPROC node
  1060.  
  1061. itexttags:
  1062.     LONG    IA_WIDTH,0,
  1063.                 IA_HEIGHT,0,
  1064.                 IA_DATA,0,
  1065.                 IA_FGPEN,0,
  1066.                 TAG_END
  1067.  
  1068. PROC disposeObjectNodes(list:PTR TO lh)
  1069.     DEF node:PTR TO imagenode,next
  1070.     node:=list.head
  1071.     IF (isempty(list)=0)
  1072.         REPEAT
  1073.             next:=node.listnode.succ
  1074.             IF (next)
  1075.                 IF (node.private_iallocated<-3)
  1076.                     Remove(node)
  1077.                     FreeMem(node,SIZEOF imagenode)
  1078.                 ENDIF
  1079.             ENDIF
  1080.             node:=next
  1081.         UNTIL (next=0)
  1082.     ENDIF
  1083. ENDPROC
  1084.  
  1085. PROC disposeObjects(list:PTR TO lh)
  1086.     DEF node:PTR TO imagenode,next
  1087.     IF (isempty(list)=0)
  1088.         node:=list.head
  1089.         REPEAT
  1090.             next:=node.listnode.succ
  1091.             IF (next)
  1092.                 IF node.private_iallocated=-5            -> A ITEXTICLASS we allocated, so we dispose the IA_DATA field.
  1093.                     IF (node.private_text) THEN DisposeLink(node.private_text)
  1094.                     IF (node.private_textfont) THEN CloseFont(node.private_textfont)
  1095.                     IF (node.private_textattr) THEN FreeMem(node.private_textattr,SIZEOF textattr)
  1096.                     IF (node.private_itextn) THEN FreeMem(node.private_itextn,SIZEOF intuitext)
  1097.                     IF (node.private_itexts) THEN FreeMem(node.private_itexts,SIZEOF intuitext)
  1098.                 ENDIF
  1099.                 IF node.object THEN DisposeObject(node.object)
  1100.                 IF node.selobject THEN DisposeObject(node.selobject)
  1101.             ENDIF
  1102.             node:=next
  1103.         UNTIL (next=0)
  1104.     ENDIF
  1105. ENDPROC
  1106.  
  1107. PROC buildPalette(firstcolor,lastcolor,width,height)
  1108.     DEF i,obj1,obj2
  1109.     DEF list:PTR TO mlh
  1110.     DEF pal1tags
  1111.     DEF pal2tags
  1112.     list:=AllocMem(SIZEOF mlh,MEMF_PUBLIC OR MEMF_CLEAR)
  1113.     newList(list)
  1114.  
  1115.     pal1tags:=New(64)
  1116.     pal2tags:=New(64)
  1117.     CopyMem({pal1taglist},pal1tags,60)
  1118.     CopyMem({pal2taglist},pal2tags,60)
  1119.     PutLong(pal1tags+4,width)
  1120.     PutLong(pal1tags+12,height)
  1121.     PutLong(pal2tags+4,width)
  1122.     PutLong(pal2tags+12,height)
  1123.     FOR i:=firstcolor TO lastcolor
  1124.         PutLong(pal1tags+20,i)
  1125.         PutLong(pal2tags+20,i)
  1126.         obj1:=NewObjectA(NIL,{fillrectclass},pal1tags)
  1127.         obj2:=NewObjectA(NIL,{fillrectclass},pal2tags)
  1128.         IF obj1
  1129.             IF obj2
  1130.                 addObjectToList(list,obj1,-1,obj2,1,BACKGROUNDPEN)
  1131.             ENDIF
  1132.         ENDIF
  1133.     ENDFOR            
  1134.     Dispose(pal1tags)
  1135.     Dispose(pal2tags)
  1136. ENDPROC list
  1137.  
  1138. pal1taglist:
  1139.     LONG IA_WIDTH,0,
  1140.                 IA_HEIGHT,0,
  1141.                 IA_FGPEN,0,
  1142.                 IA_MODE,RP_JAM2,
  1143.                 TAG_END
  1144. pal2taglist:
  1145.     LONG IA_WIDTH,0,
  1146.                 IA_HEIGHT,0,
  1147.                 IA_FGPEN,0,
  1148.                 IA_MODE,RP_JAM2,
  1149.                 TAG_END
  1150.  
  1151. PROC disposePalette(list)
  1152.     disposeObjects(list)
  1153.     disposeObjectNodes(list)
  1154.     FreeMem(list,SIZEOF mlh)
  1155. ENDPROC
  1156.  
  1157. PROC main() IS EMPTY
  1158.  
  1159. itexticlass:
  1160.     CHAR    'itexticlass',0
  1161. fillrectclass:
  1162.     CHAR    'fillrectclass',0
  1163.